<?php

namespace App\Http\Services;

use App\Exceptions\ServiceException;
use App\Exceptions\ServiceExceptionConstant;
use App\Http\Repositories\Daos\User\UserDao;
use App\Http\Repositories\Redis\UserRedis;
use App\Http\Requests\UserContext;
use App\Http\Requests\UserLogin;
use App\Http\Requests\UserRegister;
use App\Http\Traits\Errors;
use App\Models\PublishApply;
use App\Models\UserLoginLog;
use App\Models\Users;
use App\Util\Helper;
use EasyWeChat\Factory;
use GenTux\Jwt\JwtToken;
use Illuminate\Support\Facades\Log;

class UserService extends BaseService
{
    use Errors;

    protected $userDao;

    public function __construct(UserDao $userDao)
    {
        $this->userDao = $userDao;
    }

    public function loginPass(UserLogin $userLogin, JwtToken $jwtToken)
    {
        $mobile   = $userLogin->post('mobile');
        $password = $userLogin->post('password');
        //先看账号存不存在 再看注销的账号存不存在
        $user = Users::where('mobile', $mobile)->first(['id', 'mobile', 'nickname', 'email', 'avatar', 'salt', 'password', 'status', 'can_publish']);
        if (!$user) {
            $this->showError('account_invalid');
        }
//        $inputPass = Helper::password($password, $user->salt);
//        if ($inputPass != $user['password']) {
//            $this->showError('account_password_invalid');
//        }
        $clientIp = $userLogin->getClientIp();
        $this->saveLoginInfo($user->id, $userLogin, $clientIp);
        return [
            'token'     => $this->token($user, $jwtToken),
            'user_info' => [
                'nickname'    => $user['nickname'],
                'avatar'      => $user['avatar'],
                'mobile'      => $user['mobile'],
                'can_publish' => $user['can_publish']
            ]
        ];
    }

    public function registerUser(UserRegister $userRegister)
    {
        $salt   = Helper::randString(4);
        $data   = $userRegister->validationData();
        $insert = [
            'mobile'   => $data['mobile'],
            'password' => Helper::password($data['password'], $salt),
            'salt'     => $salt,
            'nickname' => '匿名用户' . time()
        ];
        Users::create($insert);
        return true;
    }

    public function token($user, $jwtToken, $is_h5 = 1)
    {
        $tokenExpireTime = 3600 * 24 * 30;//token有效期 30天 20190909 1个月

        //载体
        $jwtPayload        = [];
        $jwtPayload['iss'] = 'Kenny Hu JWT';//该JWT的签发者
        $jwtPayload['iat'] = time();//什么时候签发的
        $jwtPayload['exp'] = time() + $tokenExpireTime;//什么时候过期，这里是一个Unix时间戳
        $jwtPayload['aud'] = config('app.url');//接收该JWT的一方
        $jwtPayload['sub'] = 'All JWT';//该JWT所面向的用户
        $jwtPayload['uid'] = $user->id;//携带用户ID
        $token             = $jwtToken->createToken($jwtPayload)->token();
        $aUser             = $user->toArray();
        $aUser['token']    = $token;
        //20201016 h5端登录不把app挤掉线
        if ($is_h5 == 1) {
            $type = 'h5';
        } else {
            $type = request()->get('header_type');
        }
        if (in_array($type, ['android', 'ios'])) {
            UserRedis::getRedisInstance()->setLogin($user->id, $aUser, $tokenExpireTime);
        } else {
            UserRedis::getRedisInstance()->setLogin($user->id, $aUser, $tokenExpireTime, 2);
        }

        return $token;
    }

    /**
     * 保存最近登陆信息
     * @param $userId
     * @param $request
     * @param string $ip
     * @return mixed
     */
    private function saveLoginInfo($userId, $request, $ip = '0.0.0.0')
    {
        //保存登录日志
        $aLoginData = [
            'user_id'    => $userId,
            'login_ip'   => $ip,
            'type'       => $request->get('header_type'),
            'channel'    => $request->get('header_channel'),
            'version'    => $request->get('header_version'),
            'created_at' => date('Y-m-d H:i:s', time())
        ];
        (new UserLoginLog())->create($aLoginData);

        return true;
    }

    //小程序登录
    public function miniLogin(JwtToken $jwtToken)
    {
        $app     = Factory::miniProgram(config('wechat.mini_program.default'));
        $code    = \request('code');
        $iv      = \request('iv');
        $encData = \request('encData');
        try {
            $wechat = $app->auth->session($code);
            //$wechat中有openid
            $data = $app->encryptor->decryptData($wechat['session_key'], $iv, $encData);
        } catch (\Exception $exception) {
            Log::error('微信登录异常' . $exception->getMessage(), $wechat);
            throw new ServiceException(ServiceExceptionConstant::getErrorData('wx_api_invalid'));
        }
        if (!empty($wechat['errcode'])) {
            Log::error('获取Openid失败', $wechat);
            throw new ServiceException(ServiceExceptionConstant::getErrorData('wx_api_invalid'));
        }
        $phoneNumber = $data['phoneNumber'];
        $user        = Users::where('mobile', $phoneNumber)->first();
        if (!$user) {
            $user = Users::create(['mobile' => $phoneNumber, 'avatar' => config('app.url') . '/uploads/missing-face.png', 'nickname' => $phoneNumber, 'openid' => $wechat['openid'], 'intro' => '该用户比较懒,什么都没写', 'can_publish' => config('app.publish_verify') ? 1 : 2]);
        }
        $clientIp = request()->getClientIp();
        $this->saveLoginInfo($user->id, request(), $clientIp);
        return [
            'token'     => $this->token($user, $jwtToken),
            'user_info' => [
                'id'          => $user['id'],
                'nickname'    => $user['nickname'],
                'avatar'      => $user['avatar'],
                'mobile'      => $user['mobile'],
                'can_publish' => $user['can_publish']
            ]
        ];

    }

    public function logout(UserContext $userContext)
    {
        $userId = $userContext->getId();
        //清除用户登录信息
        UserRedis::getRedisInstance()->setLogout($userId);
        UserRedis::getRedisInstance()->deleteHash($userId);
        return true;
    }

    public function applyPublish(UserContext $userContext)
    {
        $userId = $userContext->getId();
        $start  = strtotime("-30 days");
        $info   = PublishApply::where('user_id', $userId)->first();
        if (!empty($info)) $this->showError('当前账号已申请过发布权限');
        PublishApply::create(['user_id' => $userId]);
        return true;
    }
}
